import { useRef, useCallback } from 'react'
import { SSEStatus } from '@/types/chat.d'

interface UsePostSSEParams<TRequest = any, TResponse = any> {
  url: string
  body: TRequest
  onMessage: (msg: {
    status: SSEStatus
    data: TResponse | null | string
  }) => void
}

export function usePostSSE<TRequest = any, TResponse = any>() {
  const controllerRef = useRef<AbortController | null>(null)

  const start = useCallback(
    ({ url, body, onMessage }: UsePostSSEParams<TRequest, TResponse>) => {
      const controller = new AbortController()
      controllerRef.current = controller

      fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'text/event-stream',
        },
        body: JSON.stringify(body),
        signal: controller.signal,
      })
        .then((response) => {
          if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`)
          }

          const reader = response.body?.getReader()
          const decoder = new TextDecoder('utf-8')
          let buffer = ''

          const read = () => {
            reader
              ?.read()
              .then(({ done, value }) => {
                if (done) {
                  onMessage({ status: 'closed', data: null })
                  return
                }

                buffer += decoder.decode(value, { stream: true })
                const lines = buffer.split('\n')
                buffer = lines.pop() || ''

                for (let line of lines) {
                  line = line.trim()
                  if (line.startsWith('data:')) {
                    const jsonData = line.slice(5).trim()
                    try {
                      const parsed = JSON.parse(jsonData)
                      onMessage({ status: 'message', data: parsed })
                    } catch {
                      onMessage({ status: 'error', data: jsonData })
                    }
                  }
                }

                read()
              })
              .catch((err) => {
                onMessage({ status: 'error', data: err.message })
              })
          }

          onMessage({ status: 'connecting', data: null })
          read()
        })
        .catch((err) => {
          onMessage({ status: 'error', data: err.message })
        })
    },
    []
  )

  const stop = useCallback(() => {
    controllerRef.current?.abort()
  }, [])

  return { start, stop }
}
